package com.ys168.gam.shortestpath.model;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 
 * @author Jason Krebs
 * @date 2015年2月2日
 */
public class Node {

    private static final int DEFAULT_SIZE = 50;

    private int index;
    private Image image;
    private Rectangle2D shape;
    private boolean isVisible;

    private List<Node> inNodes;
    private List<Node> outNodes;

    public Node() {
        this(0, 0);
    }

    public Node(double x, double y) {
        this(x, y, null);
    }

    public Node(double x, double y, Image image) {
        this.inNodes = new ArrayList<Node>();
        this.outNodes = new ArrayList<Node>();
        this.isVisible = true;
        this.setShape(x, y, image);
    }

    public Node(Point2D point, Image image) {
        this(point.getX(), point.getY(), image);
    }

    public void addInNode(Node node) {
        if (!containsNode(node)) {
            inNodes.add(node);
        }
    }

    public void addOutNode(Node node) {
        if (!containsNode(node)) {
            outNodes.add(node);
        }
    }

    public double calculateLength(Node other) {
        if (!containsNode(other)) {
            return Integer.MAX_VALUE;
        }

        return Point2D.distance(getLocation().getX(), getLocation().getY(), other.getLocation().getX(), other
                .getLocation().getY());
    }

    public void clearAllNodes() {
        inNodes.clear();
        outNodes.clear();
    }

    private boolean containsNode(Node node) {
        return inNodes.contains(node) || outNodes.contains(node);
    }

    public void draw(Graphics2D g2d) {
        if (!isVisible()) {
            return;
        }

        AffineTransform t = new AffineTransform();
        t.translate(getRealLocation().getX(), getRealLocation().getY());
        t.scale(1, 1);
        g2d.drawImage(getImage(), t, null);
        g2d.drawString(getIndex() + "", (float) getRealLocation().getX(), (float) getRealLocation().getY());
    }

    public List<Node> getAllNodes() {
        List<Node> allNodes = new ArrayList<Node>(inNodes);
        allNodes.addAll(outNodes);
        return allNodes;
    }

    public double getHeight() {
        return this.shape.getHeight();
    }

    public Image getImage() {
        return image;
    }

    public int getIndex() {
        return index;
    }

    public List<Node> getInNodes() {
        return Collections.unmodifiableList(inNodes);
    }

    /**
     * 获取以中心为起点的坐标
     * 
     * @return
     */
    public Point2D getLocation() {
        return new Point2D.Double(this.shape.getCenterX(), this.shape.getCenterY());
    }

    public int getNodeCount() {
        return inNodes.size() + outNodes.size();
    }

    public List<Node> getOutNodes() {
        return Collections.unmodifiableList(outNodes);
    }

    /**
     * 以左上角为中心的坐标
     * 
     * @return
     */
    public Point2D getRealLocation() {
        return new Point2D.Double(this.shape.getX(), this.shape.getY());
    }

    public Rectangle2D getShape() {
        return shape;
    }

    public double getWidth() {
        return this.shape.getWidth();
    }

    public boolean isInclude(Point2D point) {
        return this.shape.contains(point);
    }

    public boolean isVisible() {
        return isVisible;
    }

    public void removeNode(Node node) {
        inNodes.remove(node);
        outNodes.remove(node);
    }

    public void setImage(Image image) {
        setShape(getLocation().getX(), getLocation().getY(), image);
    }

    public void setIndex(int id) {
        this.index = id;
    }

    public void setLocation(double x, double y) {
        setShape(x, y, getImage());
    }

    public void setLocation(Point2D point) {
        setLocation(point.getX(), point.getY());
    }

    /**
     * maybe for fast.json
     * 
     * @param point
     */
    public void setLocation(Point2D.Double point) {
        setLocation(point.getX(), point.getY());
    }

    /**
     * 设置图形及坐标
     * 
     * @param px
     * @param py
     * @param image
     */
    private void setShape(double px, double py, Image image) {
        if (image != this.image) {
            this.image = image;
        }

        double width = this.image == null ? DEFAULT_SIZE : this.image.getWidth(null);
        double height = this.image == null ? DEFAULT_SIZE : this.image.getHeight(null);
        if (this.shape == null) {
            this.shape = new Rectangle2D.Double();
        }

        this.shape.setFrame(px - width / 2, py - height / 2, width, height);
    }

    public void setVisible(boolean isVisiable) {
        this.isVisible = isVisiable;
    }

    @Override
    public String toString() {
        return String
                .format("Node<index=%d,point=(%.2f,%.2f)>", getIndex(), getLocation().getX(), getLocation().getY());
    }
}
